// placenew1.cpp  -- new, placement new, no delete
#include <iostream>
#include <string>
#include <new>

using namespace std;
const int BUF = 512;

class JustTesting {
private:
    string words;
    int number;
public:
    JustTesting(const string &s = "Just Testing", int n = 0) {
        words = s;
        number = n;
        cout << words << " constructed\n";
    }

    ~JustTesting() { cout << words << " destroyed\n"; }

    void Show() const { cout << words << ", " << number << endl; }
};

/**关于定位new运算符的内存释放问题
 * c++ primer plus 第 p372页的demo
 * @return
 */
int main() {
    char *buffer = new char[BUF];       // get a block of memory

    JustTesting *pc1, *pc2;

    pc1 = new(buffer) JustTesting;      // place object in buffer
    pc2 = new JustTesting("Heap1", 20);  // place object on heap

    cout << "Memory block addresses:\n" << "buffer: "
         << (void *) buffer << "    heap: " << pc2
         << endl;
    cout << "Memory contents:\n";
    cout << pc1 << ": ";
    pc1->Show();
    cout << pc2 << ": ";
    pc2->Show();

    JustTesting *pc3, *pc4;
//    注意，要获取对象占用的内存大小，不能将sizeof 运算符用于 指针，否则得到的是指针自己的大小
//      sizeof (*pc) 或者 sizeof(JustTesting)
//      如果不添加 sizeof 偏移量，pc3 将会把缓冲区中的 pc1 的内容给覆盖掉
    pc3 = new(buffer + (sizeof(JustTesting))) JustTesting("Bad Idea", 6);
    pc4 = new JustTesting("Heap2", 10);
    cout << "Memory contents:\n";
    cout << pc1 << ": ";
    pc1->Show();
    cout << pc3 << ": ";
    pc3->Show();
    cout << pc4 << ": ";
    pc4->Show();

    delete pc2;                          // free Heap1         
    delete pc4;                          // free Heap2

//    注意⚠️：释放整个内存缓冲区的时候，不调用缓冲区中对象的 析构函数，
//          也就是说：缓冲区中对象所引用的内存块将导致内存泄漏

    /**
     * 也不能这样简单的释放内存
     * 原因1： delete 关键字可以与常规的new运算符配合使用，但不能与（定位new运算符）配合使用
     * 原因2： new/delete ，系统知道已分配的512字节块的buffer，
     *          但对（定位 new运算符）对该内存块做了何种处理则一无所知
     *  delete pc1;
     *  delete pc3;
     *
     *  解决方案：显式的为使用（定位new运算符）创建的对象 调用析构函数;
     *  但是要注意操作的顺序:
     *  对于使用（定位new运算符）创建的对象，应该以创建顺序相反的顺序进行删除。
     *  原因：晚创建的对象可能依赖于早创建的对象，
     *  仅当所有对象都被销毁后，才能释放用于存储这块对象的缓冲区
     * */
    pc3 -> ~JustTesting();
    pc1 -> ~JustTesting();


    delete[] buffer;                    // free buffer
    cout << "Done\n";
    // std::cin.get();
    return 0;
}
